<template>
  <view
    @mouseleave="touchsend"
    @touchcancel="touchsend"
    ref="tmspin"
    :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
  >
    <!-- #ifdef APP-NVUE -->
    <gcanvas
      v-if="show"
      @touchstart="touchstart"
      @touchmove="touchsmove"
      @touchend="touchsend"
      :id="canvasId"
      :ref="canvasId"
      class="canvas"
      :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
    >
    </gcanvas>
    <!-- #endif -->
    <!-- #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ -->
    <canvas
      @touchstart="touchstart"
      @touchmove="touchsmove"
      @touchend="touchsend"
      @mousedown="touchstart"
      @mousemove.stop="touchsmove"
      @mouseup.stop="touchsend"
      type="2d"
      id="canvasId"
      canvas-id="canvasId"
      class="canvas"
      :style="{ width: `${props.width}rpx`, height: `${props.height}rpx` }"
    ></canvas>
    <!-- #endif -->
    <!-- #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE -->
    <canvas
      @touchstart.stop="touchstart"
      @touchmove.stop="touchsmove"
      @touchend.stop="touchsend"
      @mousedown.stop="touchstart"
      @mousemove.stop="touchsmove"
      @mouseup.stop="touchsend"
      @mouseleave.stop="touchsend"
      @touchcancel.stop="touchsend"
      :id="canvasId"
      :canvas-id="canvasId"
      class="canvas"
      :style="{
        width: `${props.width}rpx`,
        height: `${props.height}rpx`,
        'touch-action': 'none',
      }"
    ></canvas>
    <!-- #endif -->
  </view>
</template>

<script lang="ts" setup>
/**
 * 签名板
 * @description 方便签名业务。在当前截止最新的3.5.0版本，uni在h5端有自身的bug无法使用。等官方修复 即可使用。
 */
import { number } from "echarts";
import {
  getCurrentInstance,
  computed,
  ref,
  ComponentInternalInstance,
  inject,
  onUpdated,
  onMounted,
  onUnmounted,
  nextTick,
  watch,
  ssrContextKey,
} from "vue";
import CanvasRenderingContext2D from "../../tool/gcanvas/context-2d/RenderingContext.js";
// #ifdef APP-NVUE
import { enable, WeexBridge } from "../../tool/gcanvas/index.js";
const dom = uni.requireNativePlugin("dom");
// #endif

const proxy = getCurrentInstance()?.proxy ?? null;

const props = defineProps({
  width: {
    type: Number,
    default: 750,
  },
  height: {
    type: Number,
    default: 500,
  },
  lineWidth: {
    type: Number,
    default: 5,
  },
  lineColor: {
    type: String,
    default: "red",
  },
});

const canvasId = ref("canvasId");
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
canvasId.value = "tm" + uni.$tm.u.getUid(5);
// #endif

let ctx: CanvasRenderingContext2D;
let canvasObject: HTMLCanvasElement;
let ctxLeft = 0;
let ctxTop = 0;
let drawhd: draw;
const show = ref(false); //安卓上首次要隐藏不然卡。
let isAndroid = false;
// #ifdef APP-NVUE
isAndroid = uni.getSystemInfoSync().osName == "android";
// #endif
onMounted(() => {
  // #ifdef APP-NVUE
  if (isAndroid) {
    setTimeout(() => {
      show.value = true;
      setTimeout(function () {
        drawNvue_init();
      }, 100);
    }, 200);
  } else {
    show.value = true;
    setTimeout(() => drawNvue_init(), 250);
  }
  // #endif

  // #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ
  setTimeout(() => MpWeix_init(), 100);
  // #endif
  // #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ || APP-NVUE
  setTimeout(() => appvueH5Other(), 50);
  // #endif
});
//appvue,h5,和其它平台。
function appvueH5Other() {
  ctx = uni.createCanvasContext(canvasId.value, proxy);
  uni
    .createSelectorQuery()
    .in(proxy)
    .select("#" + canvasId.value)
    .boundingClientRect((result) => {
      ctxLeft = result.left ?? 0;
      ctxTop = result.top ?? 0;
      drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height));
    })
    .exec();
}
function drawNvue_init() {
  /*获取元素引用*/
  var ganvas = proxy?.$refs[canvasId.value];
  /*通过元素引用获取canvas对象*/
  var canvasObj = enable(ganvas, {
    bridge: WeexBridge,
  });
  canvasObject = canvasObj;
  ctx = canvasObj.getContext("2d");
  nextTick(function () {
    setTimeout(function () {
      dom?.getComponentRect(proxy?.$refs.tmspin, function (res: any) {
        if (res?.size) {
          ctxLeft = Math.floor(res.size.left);
          ctxTop = Math.floor(res.size.top);
          drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height));
        }
      });
    }, 200);
  });
}
//支付宝和微信，QQ 支持2d渲染。
function MpWeix_init() {
  const query = uni.createSelectorQuery().in(proxy);

  // #ifdef MP-ALIPAY
  query
    .select("#canvasId")
    .node()
    .exec((res2) => {
      const canvas = res2[0].node;
      let ctxvb: UniApp.CanvasContext = canvas.getContext("2d");
      ctx = ctxvb;
      drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height));
    });
  // #endif
  // #ifdef MP-WEIXIN || MP-QQ
  query
    .select("#canvasId")
    .fields({
      node: true,
      size: true,
      rect: true,
      context: true,
    })
    .exec((res: Array<UniApp.NodeInfo>) => {
      ctxLeft = res[0].left;
      ctxTop = res[0].top;
      // #ifndef MP-QQ
      const canvas = res[0].node;
      const ctxvb = canvas.getContext("2d");
      const dpr = uni.getSystemInfoSync().pixelRatio;
      canvas.width = res[0].width * dpr;
      canvas.height = res[0].height * dpr;
      ctxvb.scale(dpr, dpr);
      ctx = ctxvb;
      canvasObject = canvas;
      drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height));
      // #endif
      // #ifdef MP-QQ
      ctx = res[0].context;
      drawhd = new draw(ctx, uni.upx2px(props.width), uni.upx2px(props.height));
      // #endif
    });
  // #endif
}

function touchstart(event: TouchEvent | MouseEvent) {
  if (!drawhd) return;
  if (event.type.indexOf("mouse") == -1 && event.changedTouches.length == 1) {
    var touch = event.changedTouches[0];
    // #ifdef APP-NVUE
    if (isAndroid) {
      drawhd.down(touch.pageX, touch.pageY);
    } else {
      drawhd.down(touch.pageX - ctxLeft, touch.pageY - ctxTop);
    }
    // #endif
    // #ifndef APP-NVUE
    drawhd.down(touch.x, touch.y);
    // #endif
  } else {
    drawhd.down(
      event.pageX - event.currentTarget.offsetLeft - ctxLeft,
      event.pageY - event.currentTarget.offsetTop - ctxTop
    );
  }
}
function touchsmove(event: TouchEvent | MouseEvent) {
  if (!drawhd) return;
  if (event?.preventDefault) event?.preventDefault();
  if (event?.stopPropagation) event?.stopPropagation();
  if (event.type.indexOf("mouse") == -1 && event.changedTouches.length == 1) {
    var touch = event.changedTouches[0];
    // #ifdef APP-NVUE
    if (isAndroid) {
      drawhd.move(touch.pageX, touch.pageY);
    } else {
      drawhd.move(touch.pageX - ctxLeft, touch.pageY - ctxTop);
    }
    // #endif
    // #ifndef APP-NVUE
    drawhd.move(touch.x, touch.y);
    // #endif
  } else {
    drawhd.move(
      event.pageX - event.currentTarget.offsetLeft - ctxLeft,
      event.pageY - event.currentTarget.offsetTop - ctxTop
    );
  }
}
function touchsend(event: TouchEvent | MouseEvent) {
  if (!drawhd) return;
  if (event.type.indexOf("mouse") == -1 && event.changedTouches.length == 1) {
    var touch = event.changedTouches[0];

    // #ifdef APP-NVUE
    if (isAndroid) {
      drawhd.up(touch.pageX, touch.pageY);
    } else {
      drawhd.up(touch.pageX - ctxLeft, touch.pageY - ctxTop);
    }
    // #endif
    // #ifndef APP-NVUE
    drawhd.up(touch.x, touch.y);
    // #endif
  } else {
    drawhd.up(
      event.pageX - event.currentTarget.offsetLeft - ctxLeft,
      event.pageY - event.currentTarget.offsetTop - ctxTop
    );
  }
}
/**
 * 清除当前画板
 */
function clear() {
  if (!ctx) {
    uni.showToast({ title: "初始化失败", icon: "none" });
    return;
  }
  ctx.clearRect(0, 0, uni.upx2px(props.width), uni.upx2px(props.height));
  // #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
  ctx.draw(false);
  // #endif
}
/**
 * 保存当前画板内容
 * 在h5端面返回的是base64位图片内容，其它端返回的是临时路径。
 */
interface imageData {
  width: number;
  height: number;
  data: ArrayBuffer;
}
function save(): Promise<string> {
  return new Promise((su, fa) => {
    if (!ctx) {
      uni.showToast({ title: "初始化失败", icon: "none" });
      fa("初始化失败");
      return;
    }
    // #ifdef APP-NVUE
    uni.showLoading({ title: "..." });
    // ctx.getImageData(0,0,props.width,props.height,function(res:imageData){
    // 	console.log(ArrayBufferToBase64(res.data).length)
    // 	fa(true)
    // 	uni.hideLoading()
    // })
    ctx.toTempFilePath(
      0,
      0,
      props.width,
      props.height,
      uni.upx2px(props.width),
      uni.upx2px(props.height),
      "png",
      1,
      function (res) {
        uni.hideLoading();
        console.log(res.errMsg);
        if (res.errMsg == "canvasToTempFilePath:ok") {
          su(res.tempFilePath);
        } else {
          fa(res.errMsg);
        }
      }
    );

    // #endif

    //webgl保存图片的方法
    // #ifndef APP-NVUE
    uni.canvasToTempFilePath(
      {
        x: 0,
        y: 0,
        destWidth: uni.upx2px(props.width),
        destHeight: uni.upx2px(props.height),
        width: props.width,
        height: props.height,
        canvasId: canvasId.value,
        canvas: canvasObject,
        success: function (res) {
          // 在H5平台下，tempFilePath 为 base64
          su(res.tempFilePath);
        },
        fail: (res) => {
          console.log("2d save img");
          fa(res);
        },
      },
      proxy
    );
    // #endif
  });
}
defineExpose({ save, clear });

interface points {
  x: number;
  y: number;
}
class draw {
  _x = 0;
  _y = 0;
  _lineWidth = 2;
  _lineColor = "black";
  cx: CanvasRenderingContext2D;
  width = 0;
  height = 0;
  _isDown = false;
  _points: Array<points> = [];
  constructor(
    ctx: CanvasRenderingContext2D,
    w: number,
    h: number,
    lineWidth = 2,
    lineColor = "black"
  ) {
    this._lineColor = lineColor;
    this._lineWidth = lineWidth;
    this.width = w;
    this.height = h;
    this.cx = ctx;
  }
  down(x = 0, y = 0) {
    this._isDown = true;
    this._x = x;
    this._y = y;
  }
  move(x = 0, y = 0) {
    if (!this._isDown) return;

    // #ifdef MP-WEIXIN || MP-ALIPAY || MP-QQ
    ctx.strokeStyle = props.lineColor;
    ctx.lineWidth = props.lineWidth;
    ctx.lineCap = "round";
    // #endif
    // #ifndef MP-WEIXIN || MP-ALIPAY || MP-QQ
    ctx.setStrokeStyle(props.lineColor);
    ctx.setLineWidth(props.lineWidth);
    ctx.setLineCap("round");
    // #endif

    ctx.beginPath();
    ctx.moveTo(this._x, this._y);
    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.closePath();

    // #ifndef MP-WEIXIN || MP-ALIPAY
    ctx.draw(true);
    // #endif
    this._x = x;
    this._y = y;
  }
  up(x = 0, y = 0) {
    this._isDown = false;
    this._x = x;
    this._y = y;
  }
}
</script>

<style scoped></style>
